package com.atguigu.gmall.cart.service;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.cart.exception.CartException;
import com.atguigu.gmall.cart.feign.GmallPmsClient;
import com.atguigu.gmall.cart.feign.GmallSmsClient;
import com.atguigu.gmall.cart.feign.GmallWmsClient;
import com.atguigu.gmall.cart.interceptor.LoginInterceptor;
import com.atguigu.gmall.cart.mapper.CartMapper;
import com.atguigu.gmall.cart.pojo.Cart;
import com.atguigu.gmall.cart.pojo.UserInfo;
import com.atguigu.gmall.common.bean.ResponseVo;
import com.atguigu.gmall.pms.entity.SkuAttrValueEntity;
import com.atguigu.gmall.pms.entity.SkuEntity;
import com.atguigu.gmall.sms.vo.ItemSaleVo;
import com.atguigu.gmall.wms.entity.WareSkuEntity;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class CartService {
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private CartAsyncService asyncService;

    @Autowired
    private GmallPmsClient pmsClient;

    @Autowired
    private GmallWmsClient wmsClient;

    @Autowired
    private GmallSmsClient smsClient;


    private static final String KEY_PREFIX = "cart:info:";
    private static final String PRICE_PREFIX = "cart:price:";

    /**
     * 新增购物车  <userId/userKye , map<skuId , cartJson>>  外层ID是对应用户,内层是对应商品的购物车信息
     *
     * @param cart skuid count
     */
    public void addCart(Cart cart) {
        //获取登录信息
        String userId = this.getUserId();

        //判断当前用户是否包含该商品
        //根据外城的userid / userKey 获取内层购物车 map<skuId , cartJson>
        BoundHashOperations<String, Object, Object> hashOps = redisTemplate.boundHashOps(KEY_PREFIX + userId);
        String skuId = cart.getSkuId().toString();
        BigDecimal count = cart.getCount(); //本次购物车新增的数量
        if (hashOps.hasKey(skuId)) { //如果购物车有对应的商品
            //如果包含,则更新商品数量
            String json = hashOps.get(skuId).toString(); //获取购物车的json字符串
            cart = JSON.parseObject(json, Cart.class); //将json 反序列化成购物车对象
            cart.setCount(cart.getCount().add(count)); //将新增的数量加入到购物车
            //将更新后的数据写入到数据库
            asyncService.updateCart(userId, skuId, cart);
        } else {
            //如果不包含,则新增记录
            cart.setUserId(userId);
            cart.setCheck(true);
            //根据skuId查询sku
            ResponseVo<SkuEntity> skuEntityResponseVo = pmsClient.querySkuById(cart.getSkuId());
            SkuEntity skuEntity = skuEntityResponseVo.getData();
            if (skuEntity == null) {
                throw new CartException("你要新增的商品不存在");
            }
            cart.setDefaultImage(skuEntity.getDefaultImage());
            cart.setTitle(skuEntity.getTitle());
            cart.setPrice(skuEntity.getPrice());

            //根据skuId查询当前sku的销售属性
            ResponseVo<List<SkuAttrValueEntity>> responseVo = pmsClient.querySaleAttrValuesBySkuId(cart.getSkuId());
            List<SkuAttrValueEntity> attrValueEntities = responseVo.getData();
            cart.setSaleAttrs(JSON.toJSONString(attrValueEntities));

            // 查询营销信息
            ResponseVo<List<ItemSaleVo>> salesResponseVo = this.smsClient.querySalesBySkuId(cart.getSkuId());
            List<ItemSaleVo> itemSaleVos = salesResponseVo.getData();
            cart.setSales(JSON.toJSONString(itemSaleVos));

            //查询是否有货
            ResponseVo<List<WareSkuEntity>> wareResponseVo = this.wmsClient.queryWareSkuBySkuid(cart.getSkuId());
            List<WareSkuEntity> wareSkuEntities = wareResponseVo.getData();
            if (!CollectionUtils.isEmpty(wareSkuEntities)) {
                cart.setStore(wareSkuEntities.stream().anyMatch(wareSkuEntity -> wareSkuEntity.getStock() - wareSkuEntity.getStockLocked() > 0));
            }
            asyncService.insertCart(cart);

            //加入购物车是,添加实时价格缓存
            redisTemplate.opsForValue().set(PRICE_PREFIX + skuId, skuEntity.getPrice().toString());
        }

        //将更新后的数据写入到redis
        hashOps.put(skuId, JSON.toJSONString(cart));
    }

    /**
     * 获取用户的登录信息
     * 登录：userId
     * 未登录：userKey
     *
     * @return
     */
    private String getUserId() {
        UserInfo userInfo = LoginInterceptor.getUserInfo();
        //默认取UserKey
        String userId = userInfo.getUserKey();

        //判断userId是否为空,不为空则说明已登录,取userId
        if (userInfo.getUserId() != null) {
            userId = userInfo.getUserId().toString();
        }
        return userId;

    }

    /**
     * 新增成功之后的查询(回显)功能
     *
     * @param skuId
     * @return
     */
    public Cart queryCartBySkuId(Long skuId) {
        //获取登录信息
        String userId = this.getUserId();

        // 获取当前用户的对应的购物车记录
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);
        if (hashOps.hasKey(skuId.toString())) {
            String json = hashOps.get(skuId.toString()).toString();
            return JSON.parseObject(json, Cart.class);
        }
        throw new CartException("您的购物车没有该商品！");
    }

    /**
     * 查询购物车
     *
     * @return
     */
    public List<Cart> queryCart() {
        UserInfo userInfo = LoginInterceptor.getUserInfo();
        String userKey = userInfo.getUserKey();
        //1.获取未登录的购物车  map<skuId , cartJson>
        BoundHashOperations<String, Object, Object> unLoginHashOps = redisTemplate.boundHashOps(KEY_PREFIX + userKey);
        List<Object> unLoginCartJson = unLoginHashOps.values();
        //如果未登录购物车不为空,则把未登录购物车的json字符串集合 转化成 未登录购物车 对象
        List<Cart> unLoginCarts = null;
        if (!CollectionUtils.isEmpty(unLoginCartJson)) {
            unLoginCarts = unLoginCartJson.stream().map(cartJson ->  {
                Cart cart = JSON.parseObject(cartJson.toString(), Cart.class);
                //设置实时价格
                cart.setCurrentPrice(new BigDecimal(redisTemplate.opsForValue().get(PRICE_PREFIX + cart.getSkuId())));
                return cart;
            }).collect(Collectors.toList());
        }

        //2.判断是否登录，未登录则直接返回未登录的购物车
        Long userId = userInfo.getUserId();
        if (userId == null) {
            return unLoginCarts;
        }

        //3.合并 未登录的购物车 到 已登录的购物车中
        // 获取已登录购物车的操作对象 Map<skuId, CartJson>
        BoundHashOperations<String, Object, Object> loginHashOps = redisTemplate.boundHashOps(KEY_PREFIX + userId);
        // 遍历未登录的购物车，合并到已登录的购物车中
        if (!CollectionUtils.isEmpty(unLoginCarts)) {
            unLoginCarts.forEach(cart -> { // 未登录购物车中的一条记录，把它合并到已登录的购物车中
                // 判断已登录购物车中是否包含 该记录
                String skuId = cart.getSkuId().toString();
                BigDecimal count = cart.getCount(); // 未登录购物车中的数量
                if (loginHashOps.hasKey(skuId)) {
                    // 包含-数量累加
                    String cartJson = loginHashOps.get(skuId).toString(); // 已登录购物车对应对应的json字符串
                    cart = JSON.parseObject(cartJson, Cart.class); // 已登录购物车的对应对象
                    cart.setCount(cart.getCount().add(count));
                    // 更新到数据库
                    asyncService.updateCart(userId.toString(), skuId, cart);
                } else {
                    // 不包含-新增记录
                    cart.setUserId(userId.toString());
                    cart.setId(null); //必须设置,否则会报错
                    asyncService.insertCart(cart);
                }
                loginHashOps.put(skuId, JSON.toJSONString(cart));
            });
            //4.清空未登录的购物车
            redisTemplate.delete(KEY_PREFIX + userKey); //删除redis数据
            asyncService.deleteByUserId(userKey); //删除mysql数据
        }
        //5.查询合并后的购物车 返回
        List<Object> loginCartJsons = loginHashOps.values();
        if (!CollectionUtils.isEmpty(loginCartJsons)){
            return loginCartJsons.stream().map(cartJson -> {
                Cart cart = JSON.parseObject(cartJson.toString(), Cart.class); //已登录购物车
                //设置实时价格  单独存储一个加入购物车时的价格 到redis
                cart.setCurrentPrice(new BigDecimal(redisTemplate.opsForValue().get(PRICE_PREFIX + cart.getSkuId())));
                return cart;
            }).collect(Collectors.toList());
        }
        return null;
    }

    /**
     * 更新
     * @param cart
     */
    public void updateNum(Cart cart) {
        // 获取登录状态
        String userId = this.getUserId();

        BoundHashOperations<String, Object, Object> hashOps = redisTemplate.boundHashOps(KEY_PREFIX + userId);
        String skuId = cart.getSkuId().toString();

        if (hashOps.hasKey(skuId)) {
            String cartJson  = hashOps.get(skuId).toString();
            BigDecimal count = cart.getCount(); // 要更新的数量

            cart = JSON.parseObject(cartJson, Cart.class);
            cart.setCount(count);

            hashOps.put(skuId, JSON.toJSONString(cart));
            asyncService.updateCart(userId, skuId, cart);
        }
    }

    /**
     * 删除
     * @param skuId
     */
    public void deleteCart(Long skuId) {
        // 获取登录状态
        String userId = this.getUserId();

        BoundHashOperations<String, Object, Object> hashOps = redisTemplate.boundHashOps(KEY_PREFIX + userId);

        hashOps.delete(skuId.toString());
        asyncService.deleteByUserIdAndSkuId(userId, skuId);
    }
}
